package com.erp.base.base;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import com.erp.base.base.dialect.MySqlDialect;
import com.erp.base.base.dialect.OracleDialect;
import com.erp.base.base.dialect.PostgreSQLDialect;

public class PageHelper {
	private static Map<String, Class<? extends Dialect>> dialectAliasMap = new HashMap<String, Class<? extends Dialect>>();
	static{ 
		dialectAliasMap.put(Dialect.DL_PGSQL, PostgreSQLDialect.class); 
		dialectAliasMap.put(Dialect.DL_MYSQL, MySqlDialect.class);
		dialectAliasMap.put(Dialect.DL_ORACLE, OracleDialect.class);
	}
	private static final List<ResultMapping> EMPTY_RESULTMAPPING = new ArrayList(0);

	private static String getDbName(DataSource dataSource) {
		Connection conn = null;
		try {
			conn = dataSource.getConnection(); 
			return conn.getMetaData().getDatabaseProductName();
			//Oracle PostgreSQL MySQL
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e1) {
				}
			}
		}
	}

	public static Dialect getDialectByDs(DataSource dataSource){
		String dbName=getDbName(dataSource);
		Class<? extends Dialect> dClazz=dialectAliasMap.get(dbName);
		if(dClazz ==null) throw new RuntimeException("无法找到数据库:"+dbName+"分页实现！");
		try { 
			return dClazz.newInstance();
		} catch (Exception e) {
			//TODO Auto-generated catch block
			throw new RuntimeException(e);
		}  
	}

	public static MappedStatement newCountMappedStatement(MappedStatement ms) {
		MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId() + "_COUNT",
				ms.getSqlSource(), ms.getSqlCommandType());
		builder.resource(ms.getResource());
		builder.fetchSize(ms.getFetchSize());
		builder.statementType(ms.getStatementType());
		builder.keyGenerator(ms.getKeyGenerator());
		if ((ms.getKeyProperties() != null) && (ms.getKeyProperties().length != 0)) {
			StringBuilder keyProperties = new StringBuilder();
			for (String keyProperty : ms.getKeyProperties()) {
				keyProperties.append(keyProperty).append(",");
			}
			keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
			builder.keyProperty(keyProperties.toString());
		}
		builder.timeout(ms.getTimeout());
		builder.parameterMap(ms.getParameterMap());

		List<ResultMap> resultMaps = new ArrayList<ResultMap>();
		ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), Long.class, EMPTY_RESULTMAPPING)
				.build();
		resultMaps.add(resultMap);
		builder.resultMaps(resultMaps);
		builder.resultSetType(ms.getResultSetType());
		builder.cache(ms.getCache());
		builder.flushCacheRequired(ms.isFlushCacheRequired());
		builder.useCache(ms.isUseCache()); 
		return builder.build();
	}

	public static Long sqlCount(MappedStatement ms,Executor executor,ResultHandler resultHandler,BoundSql boundSql,Object parameter,Map<String, Object> additionalParameters) throws Exception{
		String osql = boundSql.getSql();
		StringBuilder countSqlSB = new StringBuilder(osql.length() + 40); 
		countSqlSB.append("select count(0) from (");
		countSqlSB.append(osql);
		countSqlSB.append(") tmp_count");
		CacheKey countKey = executor.createCacheKey(ms, parameter, RowBounds.DEFAULT, boundSql);
		countKey.update("_Count");
		BoundSql countBoundSql = new BoundSql(ms.getConfiguration(), countSqlSB.toString(),
				boundSql.getParameterMappings(), parameter);
		MappedStatement countMs = newCountMappedStatement(ms); 
		for (Map.Entry<String, Object> entry : additionalParameters.entrySet()) {
			countBoundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
		}
		Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey,
				countBoundSql);
		return (Long)((List) countResultList).get(0); 
	} 

	public static Page convertParameter(Object parameterObject) {
		if (parameterObject instanceof Page) {
			return (Page) parameterObject;
		} 
		Page pg=null;
		try { 
			pg=(Page)PropertyUtils.getProperty(parameterObject, "page"); 
		} catch (Exception e) { 
			try { 
				Long offset= (Long)PropertyUtils.getProperty(parameterObject, "offset");
				Integer limit=(Integer) PropertyUtils.getProperty(parameterObject, "limit");
				pg= new Page(offset,limit);
				if(PropertyUtils.isReadable(parameterObject, "order")){
					String order = (String)PropertyUtils.getProperty(parameterObject, "order");
					pg.setOrderBy(order);
				} 
			} catch (Exception e1) { 
				pg= new Page();
			}   
		} 
		if(pg==null)
			pg=new Page();
		return pg;
	}
}
